package com.psc.view.utils;

import net.coobird.thumbnailator.Thumbnails;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Creator: Yx
 * AUTHOR: Zky
 * DATE: 2020-07-27 09:08
 * Description: 图片压缩工具
 * 压缩方式:
 * 1.先保存原图，名为：xxx.jpg或xxx.png。
 * 2.转为中等图，供网页使用，在名字后加后缀xxx_medium.jpg或xxx_medium.png。
 * 3.转为小图，供APP使用，在名字后面加后缀xxx_small.jpg或xxx_small.png。
 */
public class PicUtils {
    /**
     * 以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
     */
    private static final Logger logger = LoggerFactory.getLogger(PicUtils.class);
    private static final Integer ZERO = 0;/*图片数据必须大于0，小于0视为无效*/
    private static final Integer ONE_ZERO_TWO_FOUR = 1024;/*此处表示1024byte，也就是1KB；1KB = 1024 Byte(Byte表示字节的意思)*/
    private static final Integer NINE_ZERO_ZERO = 900;/*此处表示900KB*/
    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;/*此处表示3275KB*/
    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;/*此处表示2047KB*/
    private static final Double ZERO_EIGHT_FIVE = 0.85;/*0.85精度比例·质量*/
    private static final Double ZERO_SIX = 0.6;/*0.6精度比例·质量*/
    private static final Double ZERO_FOUR_FOUR = 0.44;/*0.44精度比例·质量*/
    private static final Double ZERO_FOUR = 0.4;/*0.4默认精度比例·质量*/

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
        //1。如果图片数据为空，或者图片数据小于或等于0，或者图片长度 小于我们要转换为的大小，则直接不压缩该图片
        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
            return imageBytes;
        }
        //2。开始压缩
        long srcSize = imageBytes.length;
        //3。调节精度 =  getAccuracy(传入计算出的图片KB大小)
        double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
        try {
            //4。开始压缩
            while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                // 5。scale 比例 scale取值越大，比例越高，1f代表原比例，0.5f代表原比例的一半，以此类推
	// scale: 缩小的倍数，1代表保持原有的大小(默认1) 范围 1 - 0
	// outputQuality : 压缩的质量，1代表保持原有的质量(默认1) 范围 1 - 0
                // 6。Output 输出流，由计算机输出到到设备或硬盘
                Thumbnails.of(inputStream)
                        .scale(1D)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("图片原大小={}kb | 压缩后大小={}kb",
                    srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度比例
     *
     * @param size 源图片KB大小
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < NINE_ZERO_ZERO) { //如果图片小于900kb
            accuracy = ZERO_EIGHT_FIVE;//精度比为0.85
        } else if (size < TWO_ZERO_FOUR_SEVEN) {//如果图片小于2047kb
            accuracy = ZERO_SIX;//精度比0.6
        } else if (size < THREE_TWO_SEVEN_FIVE) {//如果图片小于3275kb
            accuracy = ZERO_FOUR_FOUR;//精度比0.44
        } else {
            accuracy = ZERO_FOUR;//默认精度0.4
        }
        return accuracy;
    }
}
